/******************************************************************/
/*                                                                */
/*  Winpooch : Windows Watchdog                                   */
/*  Copyright (C) 2004-2005  Benoit Blanchon                      */
/*                                                                */
/*  This program is free software; you can redistribute it        */
/*  and/or modify it under the terms of the GNU General Public    */
/*  License as published by the Free Software Foundation; either  */
/*  version 2 of the License, or (at your option) any later       */
/*  version.                                                      */
/*                                                                */
/*  This program is distributed in the hope that it will be       */
/*  useful, but WITHOUT ANY WARRANTY; without even the implied    */
/*  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR       */
/*  PURPOSE.  See the GNU General Public License for more         */
/*  details.                                                      */
/*                                                                */
/*  You should have received a copy of the GNU General Public     */
/*  License along with this program; if not, write to the Free    */
/*  Software Foundation, Inc.,                                    */
/*  675 Mass Ave, Cambridge, MA 02139, USA.                       */
/*                                                                */
/******************************************************************/


/******************************************************************/
/* Includes                                                       */
/******************************************************************/

// module's interface
#include "Linked.h"

// project's headers
#include "Assert.h"

// standard headers
#include <malloc.h>


/******************************************************************/
/* Internal functions                                             */
/******************************************************************/

VOID _Linked_Lock (LINKED_LIST *) ;

VOID _Linked_Unlock (LINKED_LIST *) ;


/******************************************************************/
/* Exported function : InitList                                   */
/******************************************************************/

BOOL Linked_InitList (LINKED_LIST *pList) 
{
  // verify params
  ASSERT (pList!=NULL) ;

  // clear content
  ZeroMemory (pList, sizeof(LINKED_LIST)) ;

  // create mutex
  pList->mutex = CreateMutex (NULL, FALSE, NULL) ;

  // mutex created ?
  if( ! pList->mutex ) return FALSE ;
  
  return TRUE ;
}


/******************************************************************/
/* Exported function : UninitList                                 */
/******************************************************************/

VOID Linked_UninitList (LINKED_LIST *pList) 
{
  // verify params
  ASSERT (pList!=NULL) ;

  // destroy each node
  while( pList->length>0 ) Linked_PopBack(pList) ;
  
  // destroy mutex
  CloseHandle (pList->mutex) ;
}


/******************************************************************/
/* Exported function : Linked_PushFront                           */
/******************************************************************/

BOOL Linked_PushFront (LINKED_LIST * pList, void * pData)
{
  LINKED_NODE * pNode ;

  // verify params
  ASSERT (pList!=NULL) ;

  // alloc new node
  pNode = malloc (sizeof(LINKED_NODE)) ;
  if( ! pNode ) return FALSE ;

  // lock mutex
  _Linked_Lock (pList) ;

  // fill node
  pNode->data = pData ;
  pNode->prev = NULL ;
  pNode->next = pList->front ;

  if( pNode->next ) {
    ASSERT (pNode->next->prev==NULL) ;
    pNode->next->prev = pNode ;
  }

  pList->front = pNode ;

  if( ! pList->back ) pList->back = pNode ;

  pList->length++ ;

  // unlock mutex
  _Linked_Unlock (pList) ;

  return TRUE ;
}


/******************************************************************/
/* Exported function : PopBack                                    */
/******************************************************************/

void * Linked_PopBack (LINKED_LIST * pList) 
{
  LINKED_NODE	*pNode ;
  void		*pData ;

  // verify params
  ASSERT (pList!=NULL) ;

  // lock mutex
  _Linked_Lock (pList) ;
  
  // get address of last node
  pNode = pList->back ;

  // verify that it's really the last
  ASSERT (pNode->next==NULL) ;

  // if the list is empty, return
  if( ! pNode ) {
    _Linked_Unlock (pList) ;
    return NULL ;
  }

  if( pNode->prev ) {
    ASSERT (pNode->prev->next==pNode) ;
    pNode->prev->next = NULL ;      
  }
  
  pList->back = pNode->prev ;

  if( pList->front==pNode ) {
    ASSERT (pNode->prev==NULL) ;
    pList->front = pNode->next ;
  }

  pList->length-- ;

  // unlock mutex
  _Linked_Unlock (pList) ;

  // copy the value to return
  pData = pNode->data ;

  // free removed node
  free (pNode) ;

  return pData ;
}


/******************************************************************/
/* Internal function : Lock                                       */
/******************************************************************/

VOID _Linked_Lock (LINKED_LIST * pList) 
{
  WaitForSingleObject (pList->mutex, 1000) ;
}

VOID _Linked_Unlock (LINKED_LIST * pList) 
{
  ReleaseMutex (pList->mutex) ;
}
